﻿using Bit.Art.Core.Models;
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Diagnostics;

namespace Bit.Art.Engine
{
    /// <summary>
    /// 市场深度的订单列表，以二叉树结构来呈现
    /// </summary>
    /// <remarks>
    /// 只能单线程访问，不支持多线程处理！
    /// </remarks>
    public class OrderQueueTree
    {
        private SortedDictionary<decimal, OrderQueue> _orderbook;
        private IComparer<decimal> _comparer;

        /// <summary>
        /// 构造市场深度的订单列表
        /// </summary>
        /// <param name="capacity">为了防止内存的无限使用，订单列表的容量是固定</param>
        public OrderQueueTree(TradeSide side)
        {
            Side = side;
            _comparer = side == TradeSide.Buy ? (IComparer<decimal>)new ReverseComparer<decimal>() : Comparer<decimal>.Default;
            _orderbook = new SortedDictionary<decimal, OrderQueue>(_comparer);
        }

        /// <summary>
        /// 订单的交易方向
        /// </summary>
        public TradeSide Side { get; private set; }
        
        public volatile int _orderCount;
        /// <summary>
        /// 获取当前总订单的数量
        /// </summary>
        public int OrderCount { get { return _orderCount; } }

        /// <summary>
        /// 向订单列表里推入新订单
        /// </summary>
        /// <param name="order">订单</param>
        /// <param name="orderId">内存缓存中匹配用的order id</param>
        public void Push(Order order, out ulong orderId)
        {
            if (order == null) throw new ArgumentNullException(nameof(order));
            if (order.Price.HasValue && order.Price.Value <= 0) throw new ArgumentOutOfRangeException($"price的值必须大于0！");

            orderId = 0;
            var price = order.Price.Value;

            if (_orderbook.ContainsKey(price))
            {
                var queue = _orderbook[price];
                var added = queue.Enqueue(order, out ulong priority);
                orderId = priority;
            }
            else
            {
                var queue = new OrderQueue(); 
                var added = queue.Enqueue(order, out ulong priority);
                orderId = priority;
                _orderbook[price] = queue;
            }

            _orderCount++;
        }

        /// <summary>
        /// 返回该订单列表的市场深度
        /// </summary>
        /// <param name="limit">最多返回的深度长度，默认值是500</param>
        /// <returns>返回深度信息，二维数组格式，第一维是价格，第二维是按价格分组的数量总计，数组长度小于或等于<paramref name="limit"/>。</returns>
        public decimal[,] OrderBook(int limit = 500)
        {
            var ret = new decimal[limit, 2];
            var idx = 0;
            foreach (var item in _orderbook)
            {
                if (idx >= limit) break;
                var queue = item.Value;
                if (queue.Count == 0) continue;
                
                ret[idx, 0] = item.Key;
                ret[idx, 1] = queue.Sum(o => o.VolumeRemaining);
                idx++;
            }

            return ret;
        }

        /// <summary>
        /// 取消一个订单
        /// </summary>
        /// <param name="price">订单的价格</param>
        /// <param name="orderid">订单的内存缓存中的id</param>
        /// <returns>是否成功取消订单。</returns>
        public bool CancelOrder(decimal price, ulong orderid, ref Order memorder)
        {
            var ret = false;
            if (_orderbook.ContainsKey(price))
            {
                var queue = _orderbook[price];
                var order = queue.Remove(orderid);
                if(order != null)
                {
                    memorder.Price = order.Price;
                    memorder.Volume = order.Volume;
                    memorder.VolumeRemaining = order.VolumeRemaining;
                    memorder.LockedBalance = order.LockedBalance;
                    memorder.QuoteVolumeDealed = order.QuoteVolumeDealed;
                    memorder.UserId = order.UserId;
                    _orderCount--;
                    ret = true;
                }
            }

            return ret;
        }

        internal OrderFillType TryMatchLimit(Order order, out Order[] matched)
        {
            var price = order.Price.Value;
            matched = null;
            var lstMatchedOrders = new List<Order>();
            var lstEmptyPrices = new List<decimal>();
            foreach (var item in _orderbook)
            {
                if (item.Key <= 0m) throw new InvalidOperationException("订单撮合引擎错误，请联系管理员调查！");

                if (_comparer.Compare(price, item.Key) >= 0)
                {
                    var queue = item.Value;
                    while (queue.Count > 0 && order.VolumeRemaining > 0)
                    {
                        var top = queue.Peek();
                        if (top.UserId == order.UserId)
                            continue;
                        top.CurrentDealed = 0;
                        top.CurrentDealedQuote = 0;
                        var currentQueueVolume = top.VolumeRemaining;
                        var orderVolume = order.VolumeRemaining;
                        var dealed = Math.Min(currentQueueVolume, orderVolume);
                        var quoteVolume = top.Price.Value * dealed;

                        top.VolumeRemaining -= dealed;
                        order.VolumeRemaining -= dealed;
                        top.CurrentDealed = dealed;
                        order.CurrentDealed += dealed;
                        top.CurrentDealedQuote += quoteVolume;
                        order.CurrentDealedQuote += quoteVolume;
                        top.QuoteVolumeDealed += quoteVolume;
                        order.QuoteVolumeDealed += quoteVolume;
                        lstMatchedOrders.Add(top);

                        if (top.VolumeRemaining <= 0)
                        {
                            var matchedOrder = queue.Dequeue();
                            Debug.Assert(matchedOrder.VolumeRemaining <= 0, "被完全匹配的订单的剩余数量竟然大于0！");
                            matchedOrder.VolumeRemaining = 0;
                            _orderCount--;
                        }
                    }

                    if (queue.Count == 0)
                        lstEmptyPrices.Add(item.Key);
                }
                else
                {
                    // 没有匹配的价格！
                    break;
                }
            }

            matched = lstMatchedOrders.ToArray();

            // 已经全部匹配的价格，需要从orderbook里移除
            for (var i = 0; i < lstEmptyPrices.Count; ++i)
            {
                _orderbook.Remove(lstEmptyPrices[i]);
            }

            if (order.VolumeRemaining == order.Volume)
            {
                return OrderFillType.NotFilled;
            }
            else if (order.VolumeRemaining <= 0)
            {
                order.Taker = true;
                order.VolumeRemaining = 0;
                return OrderFillType.Filled;
            }
            else
            {
                order.Taker = true;
                return OrderFillType.PartialFilled;
            }
        }
    }
}
